﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cronus.ViewModel
{
    /// <summary>
    /// Contains base class logic and property definitions for derived classes.
    /// </summary>
    public abstract class SummaryBase
    {
        //*** Constants ***//
        //*** Static ***//
        //*** Member Variables ***//
        //*** Properties ***//
        public DateTime StartDate { get; set; }
        public DayOfWeek StartOfWeek { get; set; }

        public string HoursToday
        {
            get { return FormatHoursAsString(GetHoursToday()); }
        }

        public string HoursWeek
        {
            get { return FormatHoursAsString(GetHoursInWeek()); }
        }

        public string HoursMonth
        {
            get { return FormatHoursAsString(GetHoursInMonth()); }
        }

        public string HoursYear
        {
            get { return FormatHoursAsString(GetHoursInYear()); }
        }

        public string HoursTotal
        {
            get { return FormatHoursAsString(GetTotalHours()); }
        }

        //*** Constructors ***//
        public SummaryBase()
        {
            StartDate = DateTime.Today;
            StartOfWeek = DayOfWeek.Monday;
        }

        //*** Abstract Methods ***//
        protected abstract double QueryForHoursInRange(DateTime aStartDate, DateTime anEndDate);

        //*** Methods ***//
        /// <summary>
        /// This function will return the number of hours worked on the date specified by StartDate.
        /// </summary>
        /// <returns>Number of hours worked on this project on the StartDate.</returns>
        public double GetHoursToday()
        {
            return QueryForHoursInRange(StartDate);
        }

        /// <summary>
        /// This function returns the number of hours worked in the given week as specified by
        /// StartDate.
        /// </summary>
        /// <returns>The number of hours</returns>
        public double GetHoursInWeek()
        {
            int nStartDay = (int)StartDate.DayOfWeek;
            if (StartDate.DayOfWeek < StartOfWeek)
                nStartDay += 7;

            int nDaysAwayFromStartOfWeek = nStartDay - (int)StartOfWeek;
            DateTime aStartDate = StartDate - new TimeSpan(nDaysAwayFromStartOfWeek, 0, 0, 0);
            DateTime anEndDate = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, 23, 59, 59);
            return QueryForHoursInRange(aStartDate, anEndDate);
        }

        /// <summary>
        /// This function returns the number of hours worked on this project in the month
        /// specified by StartDate.
        /// </summary>
        /// <returns>The number of hours worked on this project in the month.</returns>
        public double GetHoursInMonth()
        {
            // Local variables
            int nYear = StartDate.Year;
            int nMonth = StartDate.Month;
            DateTime aStartDate = new DateTime(nYear, nMonth, 1);
            DateTime anEndDate = new DateTime(nYear, nMonth, DateTime.DaysInMonth(nYear, nMonth), 23, 59, 59);
            return QueryForHoursInRange(aStartDate, anEndDate);
        }

        /// <summary>
        /// This function returns the number of hours worked on this project in the year specified
        /// by StartDate.
        /// </summary>
        /// <returns>The number of hours worked on this project in the year.</returns>
        public double GetHoursInYear()
        {
            DateTime aStartDate = new DateTime(StartDate.Year, 1, 1); // Jan 1st.
            DateTime anEndDate = new DateTime(StartDate.Year, 12, 31, 23, 59, 59); // Dec 31st.
            return QueryForHoursInRange(aStartDate, anEndDate);
        }

        /// <summary>
        /// This function returns the total number of hours ever worked on this project.
        /// </summary>
        /// <returns>Total number of hours worked on this project.</returns>
        public double GetTotalHours()
        {
            return QueryForHoursInRange(DateTime.MinValue, DateTime.MaxValue);
        }

        /// <summary>
        /// This queries the dataset for hours worked on the project for the given date.
        /// </summary>
        /// <param name="aDate">The date to query on.</param>
        /// <returns>Number of hours worked on the given date.</returns>
        public double QueryForHoursInRange(DateTime aDate)
        {
            // Query for the entire given day (midnight to midnight).
            DateTime aStartTime = new DateTime(aDate.Year, aDate.Month, aDate.Day);
            DateTime anEndTime = new DateTime(aDate.Year, aDate.Month, aDate.Day, 23, 59, 59);
            return QueryForHoursInRange(aStartTime, anEndTime);
        }

        /// <summary>
        /// This function will convert a number of hours to a string (i.e.
        /// 8.5 will be returned as "8:30").
        /// </summary>
        /// <param name="dHours">The number of hours.</param>
        /// <returns>Hours in string form.</returns>
        public static string FormatHoursAsString(double dHours)
        {
            int nHours = (int)dHours;
            double dRemainder = dHours - ((int)dHours);
            int nMinutes = (int)((dRemainder * 100 * 60) / 100);

            return String.Format("{0}:{1:00}", nHours, nMinutes);
        }
    }
}
